Susipažinkite su JavaScript Module Federation dinamiškų įskiepių sistemų kūrimui. Sužinokite apie architektūrą, diegimą, saugumą ir geriausias praktikas.
JavaScript Module Federation įskiepių architektūra: dinamiškos įskiepių sistemos kūrimas
Šiuolaikinėje sudėtingoje web kūrimo aplinkoje, modulinių, mastelį keičiančių ir lengvai prižiūrimų programų kūrimas yra itin svarbus. Viena galinga technika tai pasiekti yra įskiepių architektūra, kurioje funkcionalumas yra suskaidomas į nepriklausomus, dinamiškai įkeliamus modulius. JavaScript Module Federation, Webpack 5 funkcija, suteikia tvirtą mechanizmą tokių architektūrų diegimui. Šiame straipsnyje gilinamasi į Module Federation naudojimo subtilybes kuriant dinamišką įskiepių sistemą.
Kas yra Module Federation?
Module Federation leidžia JavaScript programoms dinamiškai dalintis kodu vykdymo metu. Tai reiškia, kad modulis (kodo dalis) iš vienos programos gali būti tiesiogiai naudojamas kitoje programoje, nereikalaujant jo perkompiliavimo ar perinstaliavimo. Tai pasiekiama atveriant ir naudojant modulius tarp skirtingų kompiliavimo versijų ir net skirtingų diegimų.
Tradiciniai kodo dalinimosi metodai, tokie kaip npm paketai, reikalauja perkompiliuoti ir perinstaliuoti naudojančias programas kiekvieną kartą, kai atnaujinama bendra priklausomybė. Module Federation pašalina šią papildomą naštą, todėl idealiai tinka scenarijams, kur reikalingi dažni atnaujinimai ir nepriklausomi diegimai.
Kodėl naudoti Module Federation įskiepių architektūroms?
Module Federation siūlo keletą privalumų kuriant įskiepių architektūras:
- Dinamiškas modulių įkėlimas: Įskiepius galima įkelti ir iškelti vykdymo metu, leidžiant programoms prisitaikyti prie besikeičiančių reikalavimų, nereikalaujant pilno perinstaliavimo.
- Atsiejimas: Įskiepiai kuriami ir diegiami nepriklausomai, mažinant priklausomybes tarp skirtingų programos dalių.
- Mastelio keitimas: Programą galima lengvai išplėsti naujais įskiepiais, nepaveikiant esamo funkcionalumo.
- Priežiūros paprastumas: Įskiepius galima atnaujinti ir prižiūrėti nepriklausomai, mažinant riziką įvesti klaidas į pagrindinę programą.
- Kodo pernaudojimas: Įskiepius galima naudoti keliose programose, skatinant nuoseklumą ir mažinant kūrimo pastangas.
- Versijavimas ir atstatymas: Galite valdyti skirtingas įskiepių versijas ir prireikus lengvai atstatyti ankstesnes versijas.
Pagrindinės sąvokos: Host ir Remote konteineriai
Module Federation remiasi dviem pagrindinėmis sąvokomis:
- Host konteineris: Pagrindinė programa, kuri naudoja nuotolinius modulius (įskiepius).
- Remote konteineris: Programa, kuri atveria modulius (įskiepius), kad juos galėtų naudoti host programa.
Host konteineris dinamiškai atsiunčia „remote entry“ failą iš nuotolinio konteinerio, kuriame yra atvertų modulių manifestas. Tada host programa gali pasiekti ir naudoti šiuos modulius taip, tarsi jie būtų jos pačios kodo dalis.
Dinamiškos įskiepių sistemos diegimas su Module Federation: žingsnis po žingsnio vadovas
Panagrinėkime paprastos įskiepių sistemos kūrimo procesą naudojant Module Federation. Sukursime host programą ir nuotolinę įskiepio programą.
1. Host programos (Host konteinerio) paruošimas
Pirmiausia, sukurkite naują projekto aplanką ir inicializuokite naują npm projektą:
mkdir host-app
cd host-app
npm init -y
Įdiekite Webpack ir jo priklausomybes:
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev
Sukurkite `webpack.config.js` failą `host-app` aplanke su šia konfigūracija:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
devServer: {
port: 3000,
hot: true,
static: {
directory: path.join(__dirname, 'dist'),
},
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'Host',
remotes: {
'plugin': 'Plugin@http://localhost:3001/remoteEntry.js',
},
shared: ['react', 'react-dom'],
}),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
Paaiškinimas:
- `name`: Host programos pavadinimas.
- `remotes`: Apibrėžia nuotolinius konteinerius, kuriuos naudos host programa. Šiuo atveju, ji naudoja nuotolinį konteinerį pavadinimu `plugin` iš `http://localhost:3001/remoteEntry.js`. `Plugin@` sintaksė reiškia, kad nuotolinio ModuleFederationPlugin `name` yra 'Plugin'.
- `shared`: Išvardija priklausomybes, kurios yra bendros tarp host ir nuotolinių konteinerių. Tai apsaugo nuo pasikartojančių šių priklausomybių kopijų įkėlimo. `shared` naudojimas yra kritiškai svarbus norint išvengti klaidų ir užtikrinti tinkamą įskiepio funkcionalumą.
Sukurkite `src` aplanką ir pridėkite `index.js` failą su šiuo turiniu:
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom/client';
const PluginComponent = React.lazy(() => import('plugin/PluginComponent'));
const App = () => {
return (
<div>
<h1>Host Application</h1>
<Suspense fallback={<div>Loading Plugin...</div>}>
<PluginComponent />
</Suspense>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
Paaiškinimas:
- Mes naudojame `React.lazy` dinamiškam `PluginComponent` importavimui iš `plugin` nuotolinio modulio. Tai yra būtina norint atidėti įskiepio įkėlimą (lazy loading) ir išvengti pradinio įkrovimo vėlavimo.
- `Suspense` komponentas naudojamas įkėlimo būsenai valdyti, kol gaunamas įskiepis.
Sukurkite `public` aplanką ir pridėkite `index.html` failą su šiuo turiniu:
<!DOCTYPE html>
<html>
<head>
<title>Host Application</title>
</head>
<body>
<div id="root"></div>
<script src="./bundle.js"></script>
</body>
</html>
Pridėkite Babel konfigūracijos failą `.babelrc`:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
Atnaujinkite savo `package.json` su paleidimo skriptu:
{
"name": "host-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack serve --mode development",
"build": "webpack --mode production"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.23.9",
"@babel/preset-env": "^7.23.9",
"@babel/preset-react": "^7.23.3",
"babel-loader": "^9.1.3",
"html-webpack-plugin": "^5.6.0",
"webpack": "^5.90.3",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
2. Nuotolinės programos (įskiepio konteinerio) paruošimas
Sukurkite naują projekto aplanką įskiepiui:
mkdir plugin-app
cd plugin-app
npm init -y
Įdiekite Webpack ir jo priklausomybes:
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev
Sukurkite `webpack.config.js` failą `plugin-app` aplanke su šia konfigūracija:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
devServer: {
port: 3001,
hot: true,
static: {
directory: path.join(__dirname, 'dist'),
},
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'Plugin',
filename: 'remoteEntry.js',
exposes: {
'./PluginComponent': './src/PluginComponent',
},
shared: ['react', 'react-dom'],
}),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
Paaiškinimas:
- `name`: Nuotolinio konteinerio (įskiepio) pavadinimas. Jis **turi** sutapti su pavadinimu, naudojamu host programos `remotes` konfigūracijoje.
- `filename`: Nuotolinio įėjimo failo pavadinimas, kurį atsiųs host programa.
- `exposes`: Apibrėžia modulius, kuriuos atveria nuotolinis konteineris. Šiuo atveju, mes atveriame `PluginComponent` modulį. Raktas './PluginComponent' naudojamas host programos importavimo sakinyje (pvz., `import('plugin/PluginComponent')`).
- `shared`: Kaip ir host programoje, išvardija bendras priklausomybes. Gyvybiškai svarbu, kad bendros priklausomybės ir jų versijos būtų suderinamos tarp host ir nuotolinės programos.
Sukurkite `src` aplanką ir pridėkite `PluginComponent.jsx` failą su šiuo turiniu:
import React from 'react';
const PluginComponent = () => {
return (
<div style={{border: '1px solid blue', padding: '10px'}}>
<h2>Plugin Component</h2>
<p>This is a dynamically loaded plugin!</p>
</div>
);
};
export default PluginComponent;
Sukurkite `index.js` failą `src` aplanke, kad eksportuotumėte PluginComponent:
import PluginComponent from './PluginComponent';
export default PluginComponent;
Sukurkite `public` aplanką ir pridėkite `index.html` failą su šiuo turiniu:
<!DOCTYPE html>
<html>
<head>
<title>Plugin Application</title>
</head>
<body>
<div id="root"></div>
<script src="./bundle.js"></script>
</body>
</html>
Pridėkite Babel konfigūracijos failą `.babelrc`:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
Atnaujinkite savo `package.json` su paleidimo skriptu:
{
"name": "plugin-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack serve --mode development",
"build": "webpack --mode production"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.23.9",
"@babel/preset-env": "^7.23.9",
"@babel/preset-react": "^7.23.3",
"babel-loader": "^9.1.3",
"html-webpack-plugin": "^5.6.0",
"webpack": "^5.90.3",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
3. Programų paleidimas
Paleiskite abi, host ir įskiepio, programas, įvykdydami `npm start` jų atitinkamuose aplankuose.
Naršyklėje atidarykite `http://localhost:3000`. Turėtumėte matyti host programą su dinamiškai įkeltu įskiepio komponentu.
Pažangios funkcijos ir svarstymai
Versijavimas ir atstatymas
Module Federation palaiko versijavimą, leidžiantį valdyti skirtingas įskiepių versijas. Galite nurodyti versijų apribojimus host programos `remotes` konfigūracijoje. Pavyzdžiui:
remotes: {
'plugin': 'Plugin@http://localhost:3001/remoteEntry.js@1.0.0',
}
Tai nurodo host programai naudoti 1.0.0 įskiepio versiją. Jei yra naujesnė versija, host programa ir toliau naudos nurodytą versiją, kol ji nebus aiškiai atnaujinta. Tvirtos versijavimo sistemos diegimas yra labai svarbus siekiant išvengti kritinių pakeitimų ir užtikrinti programos stabilumą.
Saugumo aspektai
Naudojant Module Federation, saugumas yra svarbiausias. Apsvarstykite šiuos dalykus:
- Autentifikavimas ir autorizavimas: Įdiekite tinkamus autentifikavimo ir autorizavimo mechanizmus, kad užtikrintumėte, jog tik įgalioti vartotojai gali pasiekti ir naudoti įskiepius.
- Kodo vientisumas: Patikrinkite nuotolinių modulių vientisumą, kad išvengtumėte kenkėjiško kodo įterpimo į programą. Apsvarstykite galimybę naudoti Content Security Policy (CSP), kad apribotumėte šaltinius, iš kurių programa gali įkelti resursus.
- Priklausomybių valdymas: Atidžiai valdykite tiek host, tiek nuotolinių konteinerių priklausomybes, kad išvengtumėte pažeidžiamumų. Reguliariai atnaujinkite priklausomybes į naujausias versijas.
- Įvesties patvirtinimas: Patvirtinkite visus duomenis, gautus iš nuotolinių modulių, kad išvengtumėte injekcijos atakų.
- CORS (Cross-Origin Resource Sharing): Tinkamai sukonfigūruokite CORS, kad host programa galėtų pasiekti „remote entry“ failą iš įskiepio programos.
Įskiepių atradimas ir valdymas
Sudėtingesnėms įskiepių sistemoms gali prireikti mechanizmo įskiepiams atrasti ir valdyti. Tai galima pasiekti per įskiepių registrą arba atradimo paslaugą. Centrinis registras gali saugoti informaciją apie galimus įskiepius, įskaitant jų vietą, versiją ir priklausomybes. Tada host programa gali užklausti registro, kad rastų ir įkeltų tinkamus įskiepius.
Apsvarstykite šiuos metodus:
- Centralizuota konfigūracija: Saugokite įskiepių URL adresus centriniame konfigūracijos faile (pvz., JSON faile), kurį host programa nuskaito vykdymo metu. Tai leidžia lengvai pridėti, pašalinti ar atnaujinti įskiepius, neperdiegiant host programos.
- API pagrįstas atradimas: Sukurkite API galinį tašką, kuris grąžina galimų įskiepių sąrašą. Tada host programa gali gauti šį sąrašą ir dinamiškai įkelti įskiepius.
- Įvykiais pagrįsta architektūra: Naudokite įvykių magistralę (event bus) arba pranešimų eilę (message queue), kad praneštumėte host programai, kai atsiranda naujų įskiepių. Tai leidžia asinchroninį įskiepių atradimą ir įkėlimą.
Dinaminė konfigūracija ir įskiepių aktyvavimas
Leidimas vartotojams dinamiškai konfigūruoti ir aktyvuoti įskiepius yra galinga funkcija. Tam reikia mechanizmo įskiepių konfigūracijoms saugoti ir valdyti. Galite naudoti duomenų bazę, konfigūracijos failą ar debesyje esančią konfigūracijos paslaugą įskiepių nustatymams saugoti. Tada host programa gali nuskaityti šiuos nustatymus vykdymo metu ir atitinkamai aktyvuoti įskiepius. Apsvarstykite galimybę sukurti vartotojo sąsają įskiepių konfigūracijoms valdyti.
Asinchroninių operacijų ir klaidų tvarkymas
Dirbant su dinamiškai įkeliamais įskiepiais, būtina tinkamai tvarkyti asinchronines operacijas ir klaidas. Naudokite `async/await` arba Promises asinchroniniam kodui valdyti. Įdiekite tinkamą klaidų tvarkymą, kad sugautumėte ir užregistruotumėte visas klaidas, atsirandančias įskiepių įkėlimo ar vykdymo metu. Pateikite informatyvius klaidų pranešimus vartotojui. Apsvarstykite galimybę naudoti centralizuotą klaidų registravimo paslaugą, kad galėtumėte sekti klaidas visuose įskiepiuose.
Kodo skaidymas ir našumo optimizavimas
Norėdami optimizuoti našumą, naudokite kodo skaidymą (code splitting), kad suskaidytumėte programą ir įskiepius į mažesnes dalis. Tai leidžia naršyklei atsisiųsti tik tą kodą, kuris reikalingas konkrečiam puslapiui ar funkcijai. Webpack turi integruotą kodo skaidymo palaikymą. Apsvarstykite galimybę naudoti atidėtą įkėlimą (lazy loading), kad įkeltumėte įskiepius tik tada, kai jie reikalingi. Minifikuokite ir suspauskite kodą, kad sumažintumėte failo dydį.
Testavimas ir nuolatinė integracija
Kruopščiai testuokite savo įskiepių sistemą, kad įsitikintumėte, jog ji veikia teisingai. Rašykite vienetų testus (unit tests), integracijos testus (integration tests) ir visos sistemos testus (end-to-end tests). Naudokite nuolatinės integracijos (CI) sistemą, kad automatiškai paleistumėte testus kiekvieną kartą, kai keičiamas kodas. Įdiekite nuolatinio pristatymo (CD) konvejerį, kad automatizuotumėte programos ir įskiepių diegimą.
Realaus pasaulio pavyzdžiai ir naudojimo atvejai
Module Federation naudojama įvairiose realaus pasaulio programose, įskaitant:
- Elektroninės prekybos platformos: Dinamiškai įkeliant produktų rekomendacijas, mokėjimo sistemas ir siuntimo paslaugų teikėjus. Pavyzdžiui, pasaulinė elektroninės prekybos platforma galėtų naudoti Module Federation integruodama skirtingus mokėjimo paslaugų teikėjus, priklausomai nuo kliento vietos. Šiaurės Amerikoje ji galėtų įkelti „Stripe“ įskiepį, o Europoje – „PayPal“ arba „Klarna“ įskiepį.
- Turinio valdymo sistemos (TVS): Leidžiant vartotojams diegti ir aktyvuoti įskiepius, kad išplėstų TVS funkcionalumą. TVS galėtų leisti vartotojams diegti SEO optimizavimo, socialinių tinklų integracijos ar turinio analizės įskiepius.
- Informacinės paneles ir analizės platformos: Dinamiškai įkeliant skirtingus valdiklius ir vizualizacijas. Pasaulinė analizės platforma galėtų įkelti įskiepius skirtingiems duomenų šaltiniams, tokiems kaip „Google Analytics“, „Adobe Analytics“ ar „Salesforce“.
- „Microfrontend“ architektūros: Kuriant didelio masto web programas kaip nepriklausomai diegiamų „microfrontend“ rinkinį. Didelė įmonė galėtų naudoti Module Federation savo web programai kurti kaip „microfrontend“ rinkinį, kur kiekvienas atsakingas už tam tikrą verslo funkciją, pavyzdžiui, paskyros valdymą, produktų katalogą ar užsakymų apdorojimą.
- Dizaino sistemos: Dalinantis UI komponentais ir dizaino žetonais (tokens) tarp kelių programų. Pasaulinė organizacija, turinti kelis prekių ženklus, galėtų naudoti Module Federation bendrai dizaino sistemai dalintis visose savo programose, užtikrinant nuoseklumą ir mažinant kūrimo pastangas.
Geriausios praktikos kuriant dinamiškas įskiepių sistemas su Module Federation
Štai keletas geriausių praktikų, kurias reikėtų prisiminti kuriant dinamiškas įskiepių sistemas su Module Federation:
- Laikykite įskiepius mažus ir orientuotus: Kiekvienas įskiepis turėtų būti atsakingas už konkrečią funkcionalumo dalį. Tai palengvina įskiepių priežiūrą ir atnaujinimą.
- Apibrėžkite aiškias įskiepių sąsajas: Apibrėžkite aiškias sąsajas, kaip įskiepiai sąveikauja su host programa. Tai užtikrina, kad įskiepiai yra suderinami su host ir apsaugo nuo kritinių pakeitimų.
- Naudokite semantinį versijavimą: Naudokite semantinį versijavimą savo įskiepių versijoms valdyti. Tai palengvina pakeitimų sekimą ir suderinamumo užtikrinimą.
- Pateikite dokumentaciją: Pateikite aiškią ir glaustą dokumentaciją savo įskiepiams. Tai padeda vartotojams suprasti, kaip įdiegti, konfigūruoti ir naudoti įskiepius.
- Įgyvendinkite saugumo geriausias praktikas: Laikykitės saugumo geriausių praktikų, kad apsaugotumėte savo programą ir įskiepius nuo pažeidžiamumų.
- Stebėkite įskiepių našumą: Stebėkite savo įskiepių našumą, kad nustatytumėte bet kokias kliūtis. Optimizuokite kodą, kad pagerintumėte našumą.
- Automatizuokite diegimą: Automatizuokite savo programos ir įskiepių diegimą. Tai sumažina klaidų riziką ir užtikrina, kad atnaujinimai būtų greitai įdiegti.
- Naudokite nuoseklų kodavimo stilių: Užtikrinkite nuoseklų kodavimo stilių visuose įskiepiuose. Tai palengvina kodo skaitymą ir priežiūrą.
- Rašykite vienetų testus: Rašykite vienetų testus savo įskiepiams, kad įsitikintumėte, jog jie veikia teisingai.
- Naudokite linterį: Naudokite linterį, kad automatiškai patikrintumėte savo kodą dėl klaidų.
Išvada
JavaScript Module Federation suteikia galingą ir lankstų mechanizmą dinamiškoms įskiepių sistemoms kurti. Naudodami Module Federation, galite kurti modulines, mastelį keičiančias ir lengvai prižiūrimas programas, kurios gali prisitaikyti prie besikeičiančių reikalavimų. Laikydamiesi šiame straipsnyje aprašytų geriausių praktikų, galite sukurti tvirtas ir saugias įskiepių sistemas, atitinkančias jūsų organizacijos poreikius.
Ši technologija yra ypač vertinga tarptautiniame kontekste, leidžianti verslui pritaikyti savo programinės įrangos pasiūlymus konkretiems regionams ar klientų segmentams, nediegiant visiškai atskirų programų. Nuo vietinių mokėjimo sistemų integravimo iki regionui būdingo turinio pateikimo, Module Federation palengvina labiau personalizuotą ir efektyvesnę vartotojo patirtį visame pasaulyje.